package com.pickgliss.utils
{
	import com.pickgliss.instance.IManualSize;
	import com.pickgliss.ui.ComponentFactory;
	import com.pickgliss.ui.core.Component;
	import com.pickgliss.ui.core.Disposeable;
	import com.pickgliss.ui.tip.IManualTipTargetSize;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.MovieClip;
	import flash.geom.Rectangle;
	import flash.sampler.getMemberNames;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;
	import flash.utils.describeType;
	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;

	/**
	 * 
	 * @author Herman
	 * 
	 */	
	public final class ObjectUtils
	{
		
		private static var _copyAbleTypes:Vector.<String>;
		private static var _descriptOjbXMLs:Dictionary;

		/**
		 * 
		 * @param obj 用于复制的源对象
		 * @return obj 的副本
		 * 
		 */		
		public static function cloneSimpleObject(obj:Object):Object
		{
			var temp:ByteArray = new ByteArray();
			temp.writeObject(obj);
			temp.position = 0;
			return temp.readObject();
		}
		
		/**
		 * 
		 * 通过XML对目标对象进行赋值
		 * @param object: 赋值的目标对象
		 * @param data : 保存属性的XML对象
		 * 
		 */		
		public static function copyPorpertiesByXML(object:Object,data:XML):void
		{
			if(object.hasOwnProperty("beginChanges"))object["beginChanges"]();
			var attr:XMLList =data.attributes();
			for each(var item:XML in attr)
			{
				var propname:String = item.name().toString();
				if(object.hasOwnProperty(propname))
				{
//					try{
						var value:String = item.toString();
						if(value == "false")
						{
							object[propname] = false;
						}else
						{
							object[propname] = value;
						}
//					}catch(e:Error)
//					{
//						trace("错误:",e.message);
//					}
				}
			}
			if(object.hasOwnProperty("commitChanges"))object["commitChanges"]();
		}
		
		/**
		 * 
		 * @param dest 接受赋值的对象
		 * @param orig 赋值的源对象
		 * @param descriXML 该源对象的描述XML
		 * 
		 */		
		public static function copyProperties(dest:Object,orig:Object,useOrigDescript:Boolean = true):void
		{
			if(_descriptOjbXMLs == null)_descriptOjbXMLs = new Dictionary();
			var copyAbleTypes:Vector.<String> = getCopyAbleType();
			var properties:XMLList;
			var descriXML:XML;
			if(useOrigDescript)
			{
				descriXML = describeTypeSave(orig);
			}else
			{
				descriXML = describeTypeSave(dest);
			}
			
			properties = descriXML.variable;
			for each(var propertyInfo:XML in properties){
				var propertyType:String = propertyInfo.@type;
				if (copyAbleTypes.indexOf(propertyType) != -1)
				{
					var propertyName:String = propertyInfo.@name;
					if(propertyType == "Date")
					{
						dest[propertyName]  = copyDateType(orig[propertyName])
						continue;
					}
					if (dest.hasOwnProperty(propertyName))
					{
						dest[propertyName] = orig[propertyName];
					}
				}
			}
		}
		private static function copyDateType(properties:Object):Date
		{
			if(!properties)return null;
			var d:Date = new Date(properties["fullYear"], properties["month"], properties["date"], properties["hours"], properties["minutes"], properties["seconds"]);
			return d;
		}
		public static function getObjectWidth(obj:DisplayObject):Number
		{
			if(obj is IManualSize)
				return (obj as IManualSize).viewRectangle.width;
			if(obj is IManualTipTargetSize)
				return (obj as IManualTipTargetSize).manualWidth;
			if(obj is Component)
				return (obj as Component).displayWidth;
			return obj.width;
		}
		public static function getObjectHeight(obj:DisplayObject):Number
		{
			if(obj is IManualSize)
				return (obj as IManualSize).viewRectangle.height;
			if(obj is IManualTipTargetSize)
				return (obj as IManualTipTargetSize).manualHeight;
			if(obj is Component)
				return (obj as Component).displayHeight;
			return obj.height;
		}
		/**
		 * 
		 * 对所有在container容器的对象执行dispose操作
		 * @param container 存放需要dispose对象的容器
		 * 
		 */		
		public static function disposeAllChildren(container:DisplayObjectContainer):void
		{
			if(container == null)return;
			while(container.numChildren > 0)
			{
				var child:DisplayObject=container.getChildAt(0);
				ObjectUtils.disposeObject(child);
			}
		}
		/**
		 * 对container及其所有子对象的MovieClip执行stop();
		 * @param container: the container to stop
		 * 
		 */		
		public static function stopAllSubClips(container:DisplayObjectContainer):void
		{
			if(container == null)return;
			if(container is MovieClip)
			{
				(container as MovieClip).stop();
			}
			for(var i:int = 0; i < container.numChildren; i++)
			{
				var movie:DisplayObjectContainer = container.getChildAt(i) as DisplayObjectContainer;
				if(movie != null)
				{
					stopAllSubClips(movie);
				} 
				var moveClip:MovieClip = movie as MovieClip;
				if(moveClip != null)
				{
					moveClip.stop();
				}
			}
		}
		/**
		 * 
		 * 清除container下的所有显示对象
		 * @param container 被清除子对象的容器
		 * 
		 */		
		public static function removeChildAllChildren(container:DisplayObjectContainer):void
		{
			while(container.numChildren > 0)
			{
				var obj:DisplayObject = container.removeChildAt(0);
				ObjectUtils.disposeObject(obj);
			}
		}
		
		public static function removeChildAllChildrenFromStage(container:DisplayObjectContainer):void
		{
			if(!container)return;
			while(container.numChildren > 0)
			{
				container.removeChildAt(0);
			}
		}
		
		public static function disposeAllGrandson(container : DisplayObjectContainer) : void
		{
			if(container)
			{
				while(container.numChildren > 0)
				{
					var odc : DisplayObject = container.removeChildAt(0);
					if(odc is DisplayObjectContainer)
					{
						ObjectUtils.disposeAllChildren(odc as DisplayObjectContainer);
					}
					else
					{
						ObjectUtils.disposeObject(odc);
					}
					odc = null;					
				}
				ObjectUtils.disposeAllChildren(container);
			}
			container = null;
		}
		/**
		 * 循环清除，所有子级，孙子级。。。 
		 * @param container
		 * 
		 */		
		public static function disposeViolentMc(container : DisplayObjectContainer) : void
		{
			if(container)
			{
				if(container.parent)container.parent.removeChild(container);
				if(container is MovieClip)(container as MovieClip).stop();
				var count : int = container.numChildren-1;
				for(var i:int=count;i>= 0;i--)
				{
					var doc : DisplayObject = container.removeChildAt(i);
					if(!doc)continue;
					if(doc.parent)doc.parent.removeChild(doc);
					if(doc is MovieClip)(doc as MovieClip).stop();
					if(doc is DisplayObjectContainer)
					{
						disposeViolentMc(doc as DisplayObjectContainer);
					}
					else
					{
						disposeObject(doc);
						doc = null;	
					}
					
				}
				disposeObject(container);
			}
		}
		
		/**
		 * 清除对象的引用以便垃圾回收
		 * @param target : 目标对象
		 * 
		 * 支持几种对象 ：
		 * Disposeable 只执行dispose方法。
		 * Bitmap 会把bitmapData dispose 然后removeChild
		 * BitmapData 会调用dispose
		 * DisplayObject 会removeChild
		 */		
		public static function disposeObject(target:Object):void
		{
			if(target == null) return;
			if(target is Disposeable)
			{
				if(target is DisplayObject)
				{
					var targetDisplay:DisplayObject = target as DisplayObject;
					if(targetDisplay.parent)targetDisplay.parent.removeChild(targetDisplay);
				}
				Disposeable(target).dispose();
			}else if(target is Bitmap) 
			{
				var targetBitmap:Bitmap = Bitmap(target);
				if(targetBitmap.parent)targetBitmap.parent.removeChild(targetBitmap);
				if(targetBitmap.bitmapData)targetBitmap.bitmapData.dispose();
			}else if(target is BitmapData) 
			{
				var targetBitmapData:BitmapData = BitmapData(target);
				targetBitmapData.dispose();
			}
			else if(target.hasOwnProperty("dispose"))
			{
				if(target is DisplayObject)
				{
					var targetDisplay2:DisplayObject = target as DisplayObject;
					if(targetDisplay2.parent)targetDisplay2.parent.removeChild(targetDisplay2);
				}
				target["dispose"]();
			}
			else if(target is MovieClip)
			{
				var mc:MovieClip = MovieClip(target);
				mc.stop();
				if(mc.parent)mc.parent.removeChild(mc);
			}
			else if(target is DisplayObject) 
			{
				var targetDisplay1:DisplayObject = DisplayObject(target);
				if(targetDisplay1.parent)targetDisplay1.parent.removeChild(targetDisplay1);
			}
		}
		
		public static function clearDictionary(dict : Dictionary) : Dictionary
		{
			for(var key : String in dict)
			{
				delete dict[key];
			}
			return dict;
		}
		
		private static function getCopyAbleType():Vector.<String>
		{
			if(_copyAbleTypes == null)
			{
				_copyAbleTypes = new Vector.<String>();
				_copyAbleTypes.push("int");
				_copyAbleTypes.push("uint");
				_copyAbleTypes.push("String");
				_copyAbleTypes.push("Boolean");
				_copyAbleTypes.push("Number");
				_copyAbleTypes.push("Date");
			}
			return _copyAbleTypes;
		}
		/**
		 * 
		 * 安全的获取类的信息
		 * @param obj 目标对象
		 * @return 类的描述信息
		 * 
		 */		
		public static function describeTypeSave(obj:Object):XML
		{
			var result:XML
			var classname:String = getQualifiedClassName(obj);
			if(_descriptOjbXMLs[classname] != null)
			{
				result = _descriptOjbXMLs[classname];
			}else
			{
				result = describeType(obj);
				_descriptOjbXMLs[classname] = result;
			}
			return result;
		}
		
		
		public static function encode(node : String,object : Object) : XML 
		{
			var temp : String = "<" + node + " ";
			
			var classInfo : XML = describeTypeSave(object);
			if ( classInfo.@name.toString() == "Object" ) 
			{
				
				var value : Object;
				for ( var key:String in object ) 
				{
					value = object[key];
					if (!( value is Function) ) 
					{
						temp += encodingProperty(key,value);
					}
				}
			}
			else 
			{
				for each ( var v:XML in classInfo..*.( name() == "variable" || name() == "accessor" )) 
				{
					temp += encodingProperty(v.@name.toString(),object[v.@name]);
				}
			}
			temp += "/>";
			return new XML(temp);
		}
		
		private static function encodingProperty(name:String,value:Object):String
		{
			if(value is Array)
			{
				return "";
			}
			else
			{
				return escapeString(name) + "=\"" + String(value) + "\" ";
			}
		}
		
		/**
		 * Escapes a string accoding to the JSON specification.
		 *
		 * @param str The string to be escaped
		 * @return The string with escaped special characters
		 * 		according to the JSON specification
		 */
		private static function escapeString( str : String ) : String 
		{
			// create a string to store the string's jsonstring value
			var s : String = "";
			// current character in the string we're processing
			var ch : String;
			// store the length in a local variable to reduce lookups
			var len : Number = str.length;
			
			// loop over all of the characters in the string
			for ( var i : int = 0;i < len; i++ ) 
			{
				// examine the character to determine if we have to escape it
				ch = str.charAt(i);
				switch ( ch ) 
				{
					
					case '"':	
						// quotation mark
						s += "\\\"";
						break;
					
					case '/':	// solidus
						s += "\\/";
						break;
					
					case '\\':	
						// reverse solidus
						s += "\\\\";
						break;
					
					case '\b':	
						// bell
						s += "\\b";
						break;
					
					case '\f':	
						// form feed
						s += "\\f";
						break;
					
					case '\n':	
						// newline
						s += "\\n";
						break;
					
					case '\r':	
						// carriage return
						s += "\\r";
						break;
					
					case '\t':	
						// horizontal tab
						s += "\\t";
						break;
					
					default:	
						// everything else
						
						// check for a control character and escape as unicode
						if ( ch < ' ' ) 
						{
							// get the hex digit(s) of the character (either 1 or 2 digits)
							var hexCode : String = ch.charCodeAt(0).toString(16);
							
							// ensure that there are 4 digits by adjusting
							// the # of zeros accordingly.
							var zeroPad : String = hexCode.length == 2 ? "00" : "000";
							
							// create the unicode escape sequence with 4 hex digits
							s += "\\u" + zeroPad + hexCode;
						} else 
						{
							
							// no need to do any special encoding, just pass-through
							s += ch;
						}
				}
			}	
			
			return  s ;
		}
		
		/**
		 * 批量更改显示对象的visibility
		 * @param value 布尔值, 是否要显示对象
		 * @param args 显示对象集合
		 * 
		 */		
		public static function modifyVisibility(value:Boolean, ...args:Array):void{
			for (var i:int = 0; i < args.length; i++){
				(args[i] as DisplayObject).visible = value;
			}
		}
		
		/**
		 * 对显示对象的显示区域赋值
		 * @param source 显示对象
		 * @param rt 区域
		 * 
		 */
		public static function copyPropertyByRectangle(source:DisplayObject,rt:Rectangle):void
		{
			source.x = rt.x;
			source.y = rt.y;
			if(rt.width != 0)source.width = rt.width;
			if(rt.height != 0)source.height = rt.height;
		}
		
		public static function combineXML(result:XML,data:XML):void
		{
			if(data == null || result == null)
			{
				return;
			}
			var attr:XMLList =data.attributes();
			for each(var item:XML in attr)
			{
				var propname:String = item.name().toString();
				var value:String = item.toString();
				if(!result.hasOwnProperty("@"+propname))
				{
					result["@"+propname] = value;
				}
			}
		}
	}
}